package com.vip8.recorder.service.utils;


import com.vip8.recorder.service.db.model.UserInfo;
import com.vip8.recorder.service.model.LoginInfo;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jws;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.joda.time.DateTime;

import java.security.PrivateKey;
import java.security.PublicKey;
import java.util.Base64;
import java.util.Date;
import java.util.Map;
import java.util.UUID;

@Slf4j
public class JwtUtil {

    private static final String JWT_PAYLOAD_USER_KEY = "user";
    private static final String privateKey = "MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQC8I8uHpe4XWA7qdgIf2ekJkrIuLgrpOGwnoNx9hJ1cXyAz5+2zBgFM0ZJTB+mw3L7L4IZCkHew9WXC2T/zoTtZKhBdJH+Fch0nE2LKgeESGjPFNZWAJTu/vNexu2gNlzsb26RNKImD09MDzgg4m7b81Ay3QC8/LVb0uX2o1enHmGhgOUt3WUrIQVKEPi+ufgUS/RGUdin1LfXL8KHGjcFnO0qKSpt88XaSO+9Ok4Z0/O0MVY8TlyCQqFQtGNcTL0jww0RBms9yQrLAv+7FnsiynGzwwasiaQ5c01o9Ygd9s0Q5KifAu2FwueUwKf2RMtNUGCn0+e9WSHSBl5Dh8yTPAgMBAAECggEABSuSp0qnDVstJcJScp+haNLwNJatVBVp23jvNj/Ttzsh/mssPBQ5KuxDciawhFy8nYuxBNlFgMZtonon6MEQiXW/d1/OZVNqe61rtJb3IXE45P2A+0GKr803vDmjNWRnim9xx3EKvmWu0dbyoOOelroZE1wfMERFtHn4exBN2V9Jtlzy0j9beQz9A52XSM2SG3GXosYEtXiMpnvdNYhKER3GMji3x37oN9Ab41WtHXHJHB4fPsbKMV8S1DPGa+UfojLcQ2BakrocYaHASEQLrFTJMQIlC6lT+biEmolPegNiL2AMOqVb8A7SbUzyHMCJf26Sqk2FfLHJzmRD+/n1IQKBgQDziaEpd4xhXnV4EMIQ/X//nqf9TZm1dzX6T9wveT0EGjQeec9rAFNNSSzlFCSslcjV4finMl1nS1MIKfx0nJcPuPUx3WL2q7Z78gdT8AwwmwoaMc0HPhpIDeth6eCJMdy67KfouchfQmFR+3hr28ftAxm6rPu+8WOobJT8Vl8/8QKBgQDFxHK5EdPGPvIUpN1cLvOoWTnGwbjZxUmyj3r5tUscVko4Jaw6jHC3U4fne3RUqp/l/2cWqMolRtvgzAP9Td064L46cTUnOie0EoEuYGZlb3407NHzF9pEzwyYzFb9nE+dO7PpEvKkKkIMJv6xu90lt3gYcwkp94vi8QmiTHlwvwKBgBNdPyZH7i6Tzy1Tz8qADZxqphra/7zRFMapcO2Ja1OXLcu6jcaJSRZdGifA2UWrx0NSa24H8CtVbu24QO2Ywd4rK7viSYspjiH+1ZxT+vQmb8Azc4T+6CIQkUXAzey6vT1TseosU4VXhtt47lNNL3FmDLauKHo/QVhUAeiqiXpRAoGBAJikOoPbXaAav0/tu6jF2Gxsiap9pQX4Pxyhn6ISKqnxdBGICjmaYfktcKza3XvnwciMa23S00sYOOd1r/KXYZRrGIgVDph7S1+yFKDN6NqLxlZlHtrI4z/OqwNYXCAcwFo0VXUkmcDZmOa2Rki6HkNZK0l7qGwK055SukPZULYTAoGASdu47tgztN5izajn8e6V7U1baIAS/MRC67GzqPH0/mIqeKGWiQBkgMMWaxyQKfm/olU8P/llK2ZCmRVkJ0FG3FA7CuhMH2ETVVBsC5pnUEsYLSQJafzcuHNSCoAy+rpGD99eCpblwOfTYwcFG7/Ts1/7uwTyuHOIdCzDrFDPN6A=";
    private static final String publicKey = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvCPLh6XuF1gO6nYCH9npCZKyLi4K6ThsJ6DcfYSdXF8gM+ftswYBTNGSUwfpsNy+y+CGQpB3sPVlwtk/86E7WSoQXSR/hXIdJxNiyoHhEhozxTWVgCU7v7zXsbtoDZc7G9ukTSiJg9PTA84IOJu2/NQMt0AvPy1W9Ll9qNXpx5hoYDlLd1lKyEFShD4vrn4FEv0RlHYp9S31y/Chxo3BZztKikqbfPF2kjvvTpOGdPztDFWPE5cgkKhULRjXEy9I8MNEQZrPckKywL/uxZ7Ispxs8MGrImkOXNNaPWIHfbNEOSonwLthcLnlMCn9kTLTVBgp9PnvVkh0gZeQ4fMkzwIDAQAB";
    /**
     * 12小时过期
     */
    private static final Integer accessTokenExpiredTime = 12;
    /**
     * 7天过期
     */
    private static final Integer refreshTokenExpireTime = 7;


    /**
     * 获取AccessToken, 默认12小时
     *
     * @param data
     * @return
     */
    public static String generateAccessToken(UserInfo data) {
        try {
            LoginInfo userData = new LoginInfo();
            BeanCopyUtil.copyBean(data, userData);
            return generateTokenExpireInHours(userData, privateKey, 12);
        } catch (Exception e) {
            log.info(e.getMessage());
            e.printStackTrace();
        }
        return null;

    }

    /**
     * 获取RefreshToken，默认7天
     *
     * @param data
     * @return
     */
    public static String generateRefreshToken(UserInfo data) {
        try {
            LoginInfo  userData = new LoginInfo();
            BeanCopyUtil.copyBean(data, userData);
            return generateTokenExpireInDays(data, privateKey, 7);
        } catch (Exception e) {
            log.info(e.getMessage());
            e.printStackTrace();
        }
        return null;

    }


    /**
     * 私钥加密token
     *
     * @param userInfo   载荷中的数据
     * @param privateKey 私钥
     * @param expire     过期时间，单位天
     * @return JWT
     */
    public static String generateTokenExpireInDays(Object userInfo, String privateKey, int expire) throws Exception {
        PrivateKey key = RsaUtil.getPrivateKeyByStr(privateKey);
        return Jwts.builder()
                .claim(JWT_PAYLOAD_USER_KEY, JsonUtil.toJsonString(userInfo))
                .setId(createJTI())
                .setExpiration(DateTime.now().plusDays(expire).toDate())
                .signWith(key, SignatureAlgorithm.RS256)
                .compact();
    }

    /**
     * 私钥加密token
     *
     * @param userInfo   载荷中的数据
     * @param privateKey 私钥
     * @param expire     过期时间，单位小时
     * @return JWT
     */
    public static String generateTokenExpireInHours(Object userInfo, String privateKey, int expire) throws Exception {
        PrivateKey key = RsaUtil.getPrivateKeyByStr(privateKey);
        return Jwts.builder()
                .claim(JWT_PAYLOAD_USER_KEY, JsonUtil.toJsonString(userInfo))
                .setId(createJTI())
                .setExpiration(DateTime.now().plusHours(expire).toDate())
                .signWith(key, SignatureAlgorithm.RS256)
                .compact();
    }

    /**
     * 解析登录态中的用户信息
     * @param token
     * @return
     */
    public static LoginInfo parseToken(String token) {
        try {
            PublicKey key = RsaUtil.getPublicKeyByStr(publicKey);
            Jws<Claims> claimsJws = Jwts.parser().setSigningKey(key).parseClaimsJws(token);
            Claims body = claimsJws.getBody();
            LoginInfo userData =  JsonUtil.parseObject(body.get(JWT_PAYLOAD_USER_KEY).toString(), LoginInfo.class);
           return userData;
        } catch (Exception e) {
            log.info(e.getMessage());
        }
        return null;


    }


    /**
     * 公钥解析token
     *
     * @param token     用户请求中的token
     * @param publicKey 公钥
     * @return Jws<Claims>
     */
    private static Jws<Claims> parserToken(String token, String publicKey) throws Exception {
        PublicKey key = RsaUtil.getPublicKeyByStr(publicKey);
        return Jwts.parser().setSigningKey(key).parseClaimsJws(token);
    }

    private static String createJTI() {
        return new String(Base64.getEncoder().encode(UUID.randomUUID().toString().getBytes()));
    }

    /**
     * 获取token中的用户信息
     *
     * @param token     用户请求中的令牌
     * @param publicKey 公钥
     * @return 用户信息
     */
    public static <T> Payload<T> getInfoFromToken(String token, String publicKey, Class<T> userType) throws Exception {
        Jws<Claims> claimsJws = parserToken(token, publicKey);
        Claims body = claimsJws.getBody();
        Payload<T> claims = new Payload<>();
        claims.setId(body.getId());
        claims.setUserInfo(JsonUtil.parseObject(body.get(JWT_PAYLOAD_USER_KEY).toString(), userType));
        claims.setExpiration(body.getExpiration());
        return claims;
    }

    /**
     * 获取token中的载荷信息
     *
     * @param token     用户请求中的令牌
     * @param publicKey 公钥
     * @return 用户信息
     */
    public static <T> Payload<T> getInfoFromToken(String token, String publicKey) throws Exception {
        Jws<Claims> claimsJws = parserToken(token, publicKey);
        Claims body = claimsJws.getBody();
        Payload<T> claims = new Payload<>();
        claims.setId(body.getId());
        claims.setExpiration(body.getExpiration());
        return claims;
    }

    @Data
    public static class Payload<T> {

        // jwt的id
        private String id;

        // 用户信息
        private T userInfo;

        // 过期时间
        private Date expiration;

    }

    public static void main(String[] args) throws Exception {
        Map<String, Object> ketMap = RsaUtil.generateRSAKeyPair();
        String privateKeyStr = RsaUtil.getPrivateKeyStr(ketMap);
        String publicKeyStr = RsaUtil.getPublicKeyStr(ketMap);

        System.out.println(privateKeyStr);
        System.out.println("--------------------");
        System.out.println(publicKeyStr);
        System.out.println("--------------------");
        PrivateKey privateKey = RsaUtil.getPrivateKeyByStr(privateKeyStr);
        PublicKey publicKey = RsaUtil.getPublicKeyByStr(publicKeyStr);


        UserInfo userInfo = new UserInfo();
        userInfo.setId(1L);


        String token = Jwts.builder()
                .claim("user", JsonUtil.toJsonString(userInfo))
                .setId(createJTI())
                .setExpiration(DateTime.now().plusMinutes(10).toDate())
                .signWith(privateKey, SignatureAlgorithm.RS256) // 私钥加密
                // 注意这里的算法只能选RS开头的，比如还可以选SignatureAlgorithm.RS384
                .compact();

        System.out.println(token);

        Jws<Claims> claimsJws = Jwts.parser()
                .setSigningKey(publicKey) // 公钥解密
                .parseClaimsJws(token);   // token

        Claims body = claimsJws.getBody();
        System.out.println(body.get("user").toString());
    }


}



